#include <QFileInfo>
#include <QBuffer>
#include <QTime>
#include <QFile>
#include <QDate>

#include "file/CYFile.hpp"

CYFile::CYFile(QString filepath){
    this->filepath = filepath;

    this->imagesCount = 0;
    this->savedCount = 0;

    this->saved = true;

}

/*
 * 返回值解释：
 * 0 加载完成
 * 1 加载失败，无法打开文件
 * 2 加载失败，文件头异常
 * 3 加载失败，不兼容文件版本号
 */
Byte CYFile::loadFile(){
    QFile file(this->filepath);

    if(file.open(QIODevice::ReadOnly)){
        QDataStream stream(&file);

        stream.setByteOrder(QDataStream::LittleEndian);

        char header[15];
        stream.readRawData(header, 15);
        char version[2];
        stream.readRawData(version, 2);

        // 校验文件头
        if(!this->dataCompare((Byte*)header, (Byte*)this->HEADER, 15)){
            return 2;

        }

        // 校验版本号
        if(!this->dataCompare((Byte*)version, (Byte*)this->VERSION, 2)){
            return this->loadOldFile((Byte*)version, &stream);

        }

        // 读取图像数量
        stream.readRawData((char*)&this->imagesCount, 1);
        // 读取保存次数
        stream.readRawData((char*)&this->savedCount, 1);

        // 读取保存时间
        stream.readRawData((char*)&this->year, 2);
        stream.readRawData((char*)&this->month, 1);
        stream.readRawData((char*)&this->day, 1);

        stream.readRawData((char*)&this->hour, 1);
        stream.readRawData((char*)&this->minute, 1);
        stream.readRawData((char*)&this->second, 1);

        // 读取图像数据
        for(int i = 0; i < this->imagesCount; i++){
            unsigned int imageDataSize;
            stream.readRawData((char*)&imageDataSize, 4);

            char imageData[imageDataSize];
            stream.readRawData(imageData, imageDataSize);

            this->images.push_back(Image((Byte*)imageData, imageDataSize));

        }

        this->imagesCount = this->images.size();

        // 读取注释数据
        for(int i = 0; i < this->imagesCount; i++){
            Byte notesCount;
            stream.readRawData((char*)&notesCount, 1);

            for(int j = 0; j < notesCount; j++){
                unsigned short x;
                unsigned short y;

                stream.readRawData((char*)&x, 2);
                stream.readRawData((char*)&y, 2);

                // 读取初译数据
                unsigned short initialTextDataSize;
                stream.readRawData((char*)&initialTextDataSize, 2);

                char initialTextData[initialTextDataSize];
                stream.readRawData(initialTextData, initialTextDataSize);

                // 读取校对数据
                unsigned short proofreadingTextDataSize;
                stream.readRawData((char*)&proofreadingTextDataSize, 2);

                char proofreadingTextData[proofreadingTextDataSize];
                stream.readRawData(proofreadingTextData, proofreadingTextDataSize);

                // 添加注释
                Image* image = (Image*)&this->images.at(i);
                image->addNote(x, y, QString(initialTextData), QString(proofreadingTextData));

            }

        }

    }else{
        return 1;

    }

    return 0;

}

void CYFile::saveFile(){
    this->savedCount++;

    QDate date = QDate::currentDate();
    QTime time = QTime::currentTime();

    this->year   = date.year();
    this->month  = date.month();
    this->day    = date.day();

    this->hour   = time.hour();
    this->minute = time.minute();
    this->second = time.second();

    QFile file(this->filepath);

    if(file.open(QIODevice::WriteOnly | QIODevice::Truncate)){
        QDataStream stream(&file);

        stream.setByteOrder(QDataStream::LittleEndian);

        stream.writeRawData((const char*)this->HEADER, 15);
        stream.writeRawData((const char*)this->VERSION, 2);

        stream.writeRawData((const char*)&this->imagesCount, 1);
        stream.writeRawData((const char*)&this->savedCount, 1);

        // 写入保存日期
        stream.writeRawData((const char*)&this->year, 2);
        stream.writeRawData((const char*)&this->month, 1);
        stream.writeRawData((const char*)&this->day, 1);

        stream.writeRawData((const char*)&this->hour, 1);
        stream.writeRawData((const char*)&this->minute, 1);
        stream.writeRawData((const char*)&this->second, 1);

        // 写入图像数据
        for(int i = 0; i < this->imagesCount; i++){
            Image* image = (Image*)&this->images.at(i);

            QByteArray byteArray;
            QBuffer buffer(&byteArray);
            buffer.open(QIODevice::WriteOnly);
            image->getImage().save(&buffer, "PNG");
            buffer.close();

            unsigned int imageDataSize = byteArray.size();
            
            stream.writeRawData((const char*)&imageDataSize, 4);
            stream.writeRawData(byteArray.data(), imageDataSize);

        }

        // 写入注释数据
        for(int i = 0; i < this->imagesCount; i++){
            Image* image = (Image*)&this->images.at(i);

            Byte notesCount = image->getNotesCount();
            stream.writeRawData((const char*)&notesCount, 1);

            for(int j = 0; j < notesCount; j++){
                Note note = image->getNote(j);

                unsigned short x = note.getX();
                unsigned short y = note.getY();

                stream.writeRawData((const char*)&x, 2);
                stream.writeRawData((const char*)&y, 2);

                unsigned short initialTextDataSize = note.getInitialText().toStdString().size() + 1;
                stream.writeRawData((const char*)&initialTextDataSize, 2);
                stream.writeRawData(note.getInitialText().toStdString().data(), initialTextDataSize);

                unsigned short proofreadingTextDataSize = note.getProofreadingText().toStdString().size() + 1;
                stream.writeRawData((const char*)&proofreadingTextDataSize, 2);
                stream.writeRawData(note.getProofreadingText().toStdString().data(), proofreadingTextDataSize);

            }

        }

    }

    this->saved = true;
    emit fileSaved();

}

void CYFile::finalise(){
    this->savedCount = 0;

}

void CYFile::addImage(QImage image){
    this->images.push_back(Image(image));

    this->imagesCount = this->images.size();

}

void CYFile::addNote(Byte index, Note note){
    this->addNote(index, note.getX(), note.getY(), note.getInitialText(), note.getProofreadingText());

}

void CYFile::addNote(Byte index, unsigned short x, unsigned short y, QString initialText, QString proofreadingText){
    Image* image = (Image*)&this->images.at(index);
    image->addNote(x, y, initialText, proofreadingText);

    this->saved = false;
    emit fileChanged();

}

void CYFile::removeImage(Byte index){
    this->images.removeAt(index);

    this->imagesCount = this->images.size();

}

void CYFile::removeNote(Byte page, Byte index){
    Image* image = (Image*)&this->images.at(page);
    image->removeNote(index);

    this->saved = false;
    emit fileChanged();

}

void CYFile::setNoteInitialText(Byte pageIndex, Byte noteIndex, QString text){
    Image* image = (Image*)&this->images.at(pageIndex);

    if(image->getNoteInitialText(noteIndex).compare(text) != 0){
        image->setNoteInitialText(noteIndex, text);

        this->saved = false;
        emit fileChanged();

    }
    
}

void CYFile::setNoteProofreadingText(Byte pageIndex, Byte noteIndex, QString text){
    Image* image = (Image*)&this->images.at(pageIndex);

    if(image->getNoteProofreadingText(noteIndex).compare(text) != 0){
        image->setNoteProofreadingText(noteIndex, text);

        this->saved = false;
        emit fileChanged();

    }

}

void CYFile::setSaveYear(unsigned short year){
    this->year = year;

}

void CYFile::setSaveMonth(Byte month){
    this->month = month;

}

void CYFile::setSaveDay(Byte day){
    this->day = day;

}

void CYFile::setSaveHour(Byte hour){
    this->hour = hour;

}

void CYFile::setSaveMinute(Byte minute){
    this->minute = minute;

}

void CYFile::setSaveSecond(Byte second){
    this->second = second;

}

QString CYFile::getNoteInitialText(Byte pageIndex, Byte noteIndex){
    return this->getImage(pageIndex).getNoteInitialText(noteIndex);

}

QString CYFile::getNoteProofreadingText(Byte pageIndex, Byte noteIndex){
    return this->getImage(pageIndex).getNoteProofreadingText(noteIndex);

}

Byte CYFile::getImagesCount(){
    return this->imagesCount;

}

Byte CYFile::getSavedCount(){
    return this->savedCount;

}

QString CYFile::getSavedDate(){
    QString hour = this->hour > 9 ? QString("%1").arg(this->hour) : QString("0%1").arg(this->hour);
    QString minute = this->minute > 9 ? QString("%1").arg(this->minute) : QString("0%1").arg(this->minute);
    QString second = this->second > 9 ? QString("%1").arg(this->second) : QString("0%1").arg(this->second);

    return QString("%1年%2月%3日 %4:%5:%6").arg(this->year).arg(this->month).arg(this->day).arg(hour).arg(minute).arg(second);

}

Image CYFile::getImage(Byte index){
    return this->images.at(index);

}

QString CYFile::getFileName(){
    return QFileInfo(this->filepath).fileName();

}

QString CYFile::getFilePath(){
    return this->filepath;

}

bool CYFile::isSaved(){
    return this->saved;

}

Byte CYFile::loadOldFile(Byte* version, QDataStream* stream){
    if(this->dataCompare(version, (Byte*)this->VERSION_0, 2)){
        // 读取图像数量
        stream->readRawData((char*)&this->imagesCount, 1);
        // 设置保存次数
        this->savedCount = 0;

        // 设置保存时间
        // 待续

        // 读取图像数据
        for(int i = 0; i < this->imagesCount; i++){
            unsigned int imageDataSize;
            stream->readRawData((char*)&imageDataSize, 4);

            char imageData[imageDataSize];
            stream->readRawData(imageData, imageDataSize);

            this->images.push_back(Image((Byte*)imageData, imageDataSize));

            // 读取注释数据
            Byte notesCount;
            stream->readRawData((char*)&notesCount, 1);

            for(int j = 0; j < notesCount; j++){
                unsigned short x;
                unsigned short y;

                stream->readRawData((char*)&x, 2);
                stream->readRawData((char*)&y, 2);

                // 读取初译数据
                unsigned short textDataSize;
                stream->readRawData((char*)&textDataSize, 2);

                char textData[textDataSize];
                stream->readRawData(textData, textDataSize);

                Image* image = (Image*)&this->images.last();
                image->addNote(x, y, QString(textData), "");

            }

        }

    }else{
        return 3;

    }

    return 0;

}

bool CYFile::dataCompare(Byte* data1, Byte* data2, unsigned int size){
    for(unsigned int i = 0; i < size; i++){
        if(data1[i] != data2[i]){
            return false;

        }

    }

    return true;

}
